
#ifndef TOOLS_THREAD_THREADPOOL_HPP
# define TOOLS_THREAD_THREADPOOL_HPP

# include <algorithm>

# include "MessageQueue.hpp"

namespace Tools {
    namespace Thread {
        template <typename Callable>
        struct Consumer {
            Consumer() {}
            Consumer(Consumer &&) {}

            void operator()(MessageQueue<Callable> & queue) {
                while (42) {
                    Callable c = queue.receive();
                    c();
                }
            }
        };

        template <typename Callable>
        class ThreadPool {
            // static_assert() check is_callable ...
            public:
                ThreadPool(unsigned int max_threads = 4) {
                    for (unsigned int i = 0; i < max_threads; ++i)
                        this->_threads.push_back(std::thread(Consumer<Callable>(), std::ref(this->queue)));
                }

                ~ThreadPool() {
                    std::for_each(this->_threads.begin(), this->_threads.end(), [](std::thread & th) {
                        th.join();
                    });
                }

                void pushTask(Callable && task) {
                    this->queue.send(std::move(task));
                }

            public:
                MessageQueue<Callable> queue;
                std::vector<std::thread> _threads;
        };
    }
}

#endif // TOOLS_THREAD_THREADPOOL_HPP

